package com.lili.collection.core.utils;

import cn.hutool.core.collection.CollectionUtil;
import com.lili.collection.core.constans.LevelConstants;
import com.lili.collection.core.enums.FieldType;
import com.lili.collection.core.processor.JSONFullFormatFlatProcessor;
import com.lili.collection.core.processor.JSONFullFormatUnFlatProcessor;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONPath;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 *描述: JSON数据解析工具
 *@date: 2023/10/11  17:37
 *@author: lili
 */
@Slf4j
public class JsonPathAnalysisUtil {

    /**
     * 按最长路径进行添加到set集合
     * @param levelSet json路径集合
     * @param path json路径
     * @return
     */
    public static boolean appendMaxPath(Set<String> levelSet, String path) {
        if (path == null) {
            return false;
        }
        String temp = null;
        boolean flag = true;
        for (String level : levelSet) {
            if (StringUtils.isNotBlank(level) && (level.startsWith(path) || path.startsWith(level))) {
                temp = level;
                flag = false;
                break;
            }
        }
        if (CollectionUtil.isEmpty(levelSet) || flag) {
            levelSet.add(path);
            return true;
        }
        if (StringUtils.isNotBlank(temp)) {
            if (getLevelNumber(temp) < getLevelNumber(path)) {
                levelSet.remove(temp);
                levelSet.add(path);
                return true;
            }
        }
        return false;
    }

    /**
     * 获取json路径层级数量
     * @param path json路径
     * @return 层级数量
     */
    public static int getLevelNumber(String path) {
        if (StringUtils.isBlank(path)) {
            return 0;
        }
        return path.split(LevelConstants.REGEX_SPOT).length;
    }

    /**
     * 创建可存储的值，将json对象转换为json字符串
     * @param objValue 存储对象
     * @return json字符串
     */
    public static Object createSaveValue(Object objValue) {
        if (objValue instanceof JSONArray || objValue instanceof JSONObject) {
            return JSON.toJSONString(objValue);
        } else {
            return DateConvertUtil.dateTypeHandle(objValue);
        }
    }

    public static String getSuffixPath(String fullPath, String prefix) {
        if (StringUtils.isNotBlank(prefix)
                && StringUtils.isNotBlank(fullPath)
                && fullPath.startsWith(prefix)
                && !fullPath.equals(prefix)) {
            return fullPath.substring(prefix.length()+1);
        } else if (StringUtils.isBlank(prefix) && StringUtils.isNotBlank(fullPath)) {
            return fullPath;
        }
        return null;
    }

    public static String getParentPath(String path) {
        if (StringUtils.isBlank(path)) {
            return path;
        }
        int index = path.lastIndexOf(LevelConstants.SPOT);
        if (index != -1) {
            return path.substring(0, index);
        } else {
            return path;
        }
    }

    /**
     * 获取指定层级数下的json路径
     * @param path json路径
     * @param levelNumber 层级数
     */
    public static String choosePathByNum(String path, int levelNumber) {
        if (StringUtils.isBlank(path) || levelNumber <= 0) {
            return null;
        }
        String[] paths = path.split(LevelConstants.REGEX_SPOT);
        if (levelNumber > paths.length) {
            return null;
        }
        StringBuilder choosePath = new StringBuilder();
        for (int i = 0; i < levelNumber; i++) {
            if (i == 0) {
                choosePath.append(paths[i]);
            } else {
                choosePath.append(LevelConstants.SPOT).append(paths[i]);
            }
        }
        return choosePath.toString();
    }

    /**
     * 获取指定层级数下的key值
     * @param path json路径
     * @param levelNumber 层级数
     */
    public static String getPathKeyByNum(String path, int levelNumber) {
        if (StringUtils.isBlank(path) || levelNumber <= 0) {
            return null;
        }
        String[] paths = path.split(LevelConstants.REGEX_SPOT);
        if (levelNumber > paths.length) {
            return null;
        }
        return paths[levelNumber-1];
    }

    public static FieldType getFieldType(String key){
        if(StringUtils.isBlank(key)){
            return null;
        }
        if(key.endsWith(LevelConstants.ARRAY)){
            return FieldType.ARRAY;
        }
        if(key.endsWith(LevelConstants.OBJECT)){
            return FieldType.OBJECT;
        }
        if(key.endsWith(LevelConstants.ARRAY_BASE)){
            return FieldType.ARRAY_BASE;
        }
        return FieldType.BASE;
    }

    public static String getRealKey(String key){
        if(StringUtils.isBlank(key)){
            return key;
        }
        if(key.endsWith(LevelConstants.ARRAY)){
            return key.replace(LevelConstants.ARRAY,LevelConstants.BLANK_STR);
        }
        if(key.endsWith(LevelConstants.OBJECT)){
            return key.replace(LevelConstants.OBJECT,LevelConstants.BLANK_STR);
        }
        if(key.endsWith(LevelConstants.ARRAY_BASE)){
            return key.replace(LevelConstants.ARRAY_BASE,LevelConstants.BLANK_STR);
        }
        return key;
    }

    /**
     * 获取json路径的字段
     * @param path json路径
     * @return 子字段
     */
    public static String getPathField(String path) {
        if (StringUtils.isBlank(path)) {
            return path;
        }
        int index = path.lastIndexOf(LevelConstants.SPOT);
        if (index != -1) {
            return path.substring(index + 1, path.length());
        } else {
            return path;
        }
    }

    /**
     * 判断目标路径是否包含数组或者对象
     * @param pathMap 路径映射
     */
    public static boolean hasArrayOrObject(Map<String,String> pathMap){
        if(MapUtils.isEmpty(pathMap)){
            return false;
        }
        for (String levelName : pathMap.values()) {
            if(StringUtils.isBlank(levelName)){
                continue;
            }
            if(levelName.contains(LevelConstants.ARRAY)){
                return true;
            }
            if(levelName.contains(LevelConstants.OBJECT)){
                return true;
            }
        }
        return false;
    }


    /**
     * 根据路径收集值
     * @param response 响应数据
     * @param basePath 数据路径
     */
    public static Object getJsonValueByPath(String response, String basePath){
        if(StringUtils.isBlank(basePath)){
            return JSON.parse(response);
        }
        if(JSON.isValidArray(response)){
            List<Object> dataList=new ArrayList<>();
            for (Object obj : JSON.parseArray(response)) {
                if(obj instanceof JSONObject){
                    dataList.add(((JSONObject)obj).eval(JSONPath.of(LevelConstants.PATH_PREFIX + basePath)));
                }
            }
            return dataList;
        }else if(JSON.isValidObject(response)){
            return JSON.parseObject(response).eval(JSONPath.of(LevelConstants.PATH_PREFIX + basePath));
        }else {
            throw new IllegalArgumentException("响应数据格式不是JSON格式！");
        }
    }

    /**
     * 提取真实路径
     * @param path 原始路径
     * @return
     */
    public static String extractRealPath(String path) {
        if(StringUtils.isBlank(path) || !path.contains(LevelConstants.ARRAY_LEFT)
                || !path.contains(LevelConstants.ARRAY_RIGHT) ){
            return path;
        }
        String[] split = path.split(LevelConstants.REGEX_SPOT);
        StringBuilder builder=new StringBuilder();
        for (int i = 0; i < split.length; i++) {
            String realKey = extractRealKey(split[i]);
            if (i == 0) {
                builder.append(realKey);
            } else {
                builder.append(LevelConstants.SPOT).append(realKey);
            }
        }
        if(builder.charAt(0)==LevelConstants.SPOT_CHAR){
            return builder.deleteCharAt(0).toString();
        }else {
            return builder.toString();
        }
    }

    /**
     * 提取真实路径
     * @param path 原始路径
     * @return
     */
    public static String getRealPathByTarget(String path) {
        if(StringUtils.isBlank(path) || !(path.contains(LevelConstants.OBJECT)
                || path.contains(LevelConstants.ARRAY)
                || path.contains(LevelConstants.ARRAY_BASE))){
            return path;
        }
        String[] split = path.split(LevelConstants.REGEX_SPOT);
        StringBuilder builder=new StringBuilder();
        for (int i = 0; i < split.length; i++) {
            String realKey = getRealKey(split[i]);
            if (i == 0) {
                builder.append(realKey);
            } else {
                builder.append(LevelConstants.SPOT).append(realKey);
            }
        }
        if(builder.charAt(0)==LevelConstants.SPOT_CHAR){
            return builder.deleteCharAt(0).toString();
        }else {
            return builder.toString();
        }
    }

    /**
     * 提取真实key字段
     * @param value 原始key
     */
    private static String extractRealKey(String value){
        if(StringUtils.isBlank(value)){
            return value;
        }
        int leftIndex = value.indexOf(LevelConstants.ARRAY_LEFT);
        if(leftIndex!=-1){
            return value.substring(0,leftIndex);
        }else {
            return value;
        }
    }

    public static String extractArrIdx(String value){
        if(StringUtils.isBlank(value)){
            return null;
        }
        int leftIndex = value.indexOf(LevelConstants.ARRAY_LEFT);
        int rightIndex = value.indexOf(LevelConstants.ARRAY_RIGHT);
        if(leftIndex!=-1 && rightIndex!=-1){
            return value.substring(leftIndex,rightIndex+1);
        }else {
            return null;
        }
    }

    public static boolean hasArray(String value){
        if(StringUtils.isBlank(value)){
            return false;
        }
        int leftIndex = value.indexOf(LevelConstants.ARRAY_LEFT);
        int rightIndex = value.indexOf(LevelConstants.ARRAY_RIGHT);
        return leftIndex!=-1 && rightIndex!=-1;
    }

    public static boolean isFirstArray(String value){
        if(StringUtils.isBlank(value)){
            return false;
        }
        return value.startsWith(LevelConstants.ARRAY_LEFT);
    }

    /**
     * 转换为目标层级路径
     * @param originPath 原始结构路径
     * @param newPath 目标结构路径
     * @return 转换后路径
     */
    public static String createConvertPath(String originPath, String newPath) {
        if (StringUtils.isBlank(originPath) || StringUtils.isBlank(newPath)) {
            throw new IllegalArgumentException("映射路径不能为空！");
        }
        if(!hasArray(originPath)){
            return newPath;
        }
        String realPath = extractRealPath(originPath);
        int realPathNumber = getLevelNumber(realPath);
        int newPathNumber = getLevelNumber(newPath);
        if (realPathNumber != newPathNumber) {
            throw new IllegalArgumentException("原路径：【" + realPath + "】与目标路径：【" + newPath + "】结构不匹配！");
        }
        String[] originKey = originPath.split(LevelConstants.REGEX_SPOT);
        String[] newKey = newPath.split(LevelConstants.REGEX_SPOT);
        boolean isHeadArray = false;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < originKey.length; i++) {
            String key = originKey[i];
            if (i == 0 && isFirstArray(key)) {
                isHeadArray = true;
                builder.append(key).append(LevelConstants.SPOT);
            } else {
                int newKeyIdx = isHeadArray ? i - 1 : i;
                String idx = extractArrIdx(key);
                if (StringUtils.isNotBlank(idx)) {
                    builder.append(newKey[newKeyIdx]).append(idx).append(LevelConstants.SPOT);
                } else {
                    builder.append(newKey[newKeyIdx]).append(LevelConstants.SPOT);
                }
            }
        }
        if (builder.charAt(builder.length() - 1) == LevelConstants.SPOT_CHAR) {
            return builder.deleteCharAt(builder.length() - 1).toString();
        }
        return builder.toString();
    }

    /**
     * 创建转换后的json数据
     * @param response 待处理json格式值
     * @param aliasMap 映射
     * @param basePath 提取根路径
     */
    public static String getConvertJson(String response,Map<String, String> aliasMap, String basePath) {
        if(MapUtils.isEmpty(aliasMap) || StringUtils.isBlank(response)){
            return null;
        }
        Object object = getJsonValueByPath(response, basePath);
        if(object==null){
            return null;
        }
        Map<String, Object> flatMap = JSONFullFormatFlatProcessor.jsonFlattenAsMap(object);
        Map<String,Object> convertNameMap=new LinkedHashMap<>();
        for (Map.Entry<String, Object> entry : flatMap.entrySet()) {
            String realPath = extractRealPath(entry.getKey());
            String convertName = aliasMap.get(appendPrefixPath(basePath,realPath));
            if (StringUtils.isNotBlank(convertName)) {
                convertNameMap.put(createConvertPath(entry.getKey(),convertName),entry.getValue());
            }
        }
        if(MapUtils.isNotEmpty(convertNameMap)){
            return JSONFullFormatUnFlatProcessor.unflatten(convertNameMap);
        }
        return null;
    }

    private static String appendPrefixPath(String prefix,String path){
        if(StringUtils.isBlank(prefix) || StringUtils.isBlank(path)){
            return path;
        }
        return prefix.concat(".").concat(path);
    }

    /**
     * 获取所有对象路径
     */
    public static Set<String> getAllObjPath(JSONObject jsonObject){
        if(MapUtils.isEmpty(jsonObject)){
            return null;
        }
        Set<String> objectPathSet=new HashSet<>();
        findAllObject(jsonObject,objectPathSet,null);
        return objectPathSet;
    }

    /**
     * 递归获取所有对象路径
     * @param jsonObject 原参数
     * @param objectPathSet 收集的对象集合
     * @param key 当前key
     */
    private static void findAllObject(JSONObject jsonObject,Set<String> objectPathSet,String key) {
        for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
            if(entry.getValue() instanceof JSONObject){
                String realKey= StringUtils.isNotBlank(key)? key+"."+entry.getKey():entry.getKey();
                objectPathSet.add(realKey);
                findAllObject((JSONObject)entry.getValue(),objectPathSet,realKey);
            }
        }
    }
}